//
//  PKSplitVideoComposer.swift
//  GoAbroad
//
//  Created by Pink Snow on 2025/6/3.
//

import Foundation
import AVFoundation
import UIKit

@available(iOS 16.0, *)
class SplitVideoComposer {

    struct Config {
        let videoURL: URL
        let image: UIImage
        let outputURL: URL
        let fps: Int32
        let outputSize: CGSize? // 若为 nil，则使用视频原始宽度 * 高度*2
    }

    func compose(with config: Config) async throws -> URL {
        let asset = AVAsset(url: config.videoURL)

        let tracks = try await asset.loadTracks(withMediaType: .video)
        guard let videoTrack = tracks.first else {
            throw NSError(domain: "SplitVideoComposer", code: -1, userInfo: [NSLocalizedDescriptionKey: "找不到视频轨道"])
        }

        let naturalSize = try await videoTrack.load(.naturalSize)
        let transform = try await videoTrack.load(.preferredTransform)
        let originalSize = naturalSize.applying(transform)
        let videoSize = CGSize(width: abs(originalSize.width), height: abs(originalSize.height))
        let renderSize = config.outputSize ?? CGSize(width: videoSize.width, height: videoSize.height * 2)

        // 构建 Composition
        let composition = AVMutableComposition()
        guard let compTrack = composition.addMutableTrack(withMediaType: .video,
                                                           preferredTrackID: kCMPersistentTrackID_Invalid) else {
            throw NSError(domain: "SplitVideoComposer", code: -2, userInfo: [NSLocalizedDescriptionKey: "无法创建合成轨道"])
        }

        try await compTrack.insertTimeRange(CMTimeRange(start: .zero, duration: asset.load(.duration)), of: videoTrack, at: .zero)
        compTrack.preferredTransform = transform

        // 构建图层
        let videoLayer = CALayer()
        videoLayer.frame = CGRect(x: 0, y: 0, width: renderSize.width, height: renderSize.height / 2)

        let imageLayer = CALayer()
        imageLayer.contents = config.image.cgImage
        imageLayer.contentsGravity = .resizeAspectFill
        imageLayer.frame = CGRect(x: 0, y: renderSize.height / 2, width: renderSize.width, height: renderSize.height / 2)
        imageLayer.masksToBounds = true

        let parentLayer = CALayer()
        parentLayer.frame = CGRect(origin: .zero, size: renderSize)
        parentLayer.addSublayer(videoLayer)
        parentLayer.addSublayer(imageLayer)

        // 视频合成配置
        let videoComposition = AVMutableVideoComposition()
        videoComposition.renderSize = renderSize
        videoComposition.frameDuration = CMTime(value: 1, timescale: config.fps)

        let instruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)

        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: compTrack)
        instruction.layerInstructions = [layerInstruction]
        videoComposition.instructions = [instruction]
        videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)

        // 导出设置
        try? FileManager.default.removeItem(at: config.outputURL)

        guard let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {
            throw NSError(domain: "SplitVideoComposer", code: -3, userInfo: [NSLocalizedDescriptionKey: "无法创建导出会话"])
        }

        exporter.outputURL = config.outputURL
        exporter.outputFileType = .mp4
        exporter.videoComposition = videoComposition

        return try await withCheckedThrowingContinuation { continuation in
            exporter.exportAsynchronously {
                switch exporter.status {
                case .completed:
                    continuation.resume(returning: config.outputURL)
                case .failed, .cancelled:
                    continuation.resume(throwing: exporter.error ?? NSError(domain: "SplitVideoComposer", code: -4, userInfo: [NSLocalizedDescriptionKey: "导出失败"]))
                default:
                    break
                }
            }
        }
    }
}
